import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'dart:developer' as developer;
import 'package:dio/dio.dart';

/// MinIO图片提供器
/// 使用Dio客户端加载MinIO预签名URL的图片
class MinioImageProvider extends ImageProvider<MinioImageProvider> {
  /// 图片URL
  final String url;

  /// 请求头
  final Map<String, String>? headers;

  /// 缩放
  final double scale;

  /// 创建MinioImageProvider
  const MinioImageProvider(this.url, {this.headers, this.scale = 1.0});

  /// 处理预签名URL，确保正确的Content-Type
  String _processUrl(String url) {
    try {
      final uri = Uri.parse(url);
      final params = Map<String, String>.from(uri.queryParameters);

      // 检查文件扩展名
      final path = uri.path.toLowerCase();
      String contentType = 'image/jpeg'; // 默认为JPEG

      if (path.endsWith('.png')) {
        contentType = 'image/png';
      } else if (path.endsWith('.gif')) {
        contentType = 'image/gif';
      } else if (path.endsWith('.webp')) {
        contentType = 'image/webp';
      } else if (path.endsWith('.jpg') || path.endsWith('.jpeg')) {
        contentType = 'image/jpeg';
      }

      // 更新或添加 response-content-type 参数
      params['response-content-type'] = contentType;

      // 重建URL
      final newUri = uri.replace(queryParameters: params);
      developer.log('处理后的URL: $newUri', name: 'MinioImageProvider');
      return newUri.toString();
    } catch (e) {
      developer.log('URL处理错误: $e', name: 'MinioImageProvider');
      return url;
    }
  }

  @override
  Future<MinioImageProvider> obtainKey(ImageConfiguration configuration) {
    return SynchronousFuture<MinioImageProvider>(this);
  }

  @override
  ImageStreamCompleter loadImage(
    MinioImageProvider key,
    ImageDecoderCallback decode,
  ) {
    final StreamController<ImageChunkEvent> chunkEvents =
        StreamController<ImageChunkEvent>();

    return MultiFrameImageStreamCompleter(
      codec: _loadAsync(key, decode, chunkEvents),
      chunkEvents: chunkEvents.stream,
      scale: key.scale,
      debugLabel: key.url,
      informationCollector: () sync* {
        yield ErrorDescription('Image URL: ${key.url}');
        yield ErrorDescription('Scale: ${key.scale}');
        if (key.headers != null) {
          yield ErrorDescription('Headers: ${key.headers}');
        }
      },
    );
  }

  /// 异步加载图片
  Future<ui.Codec> _loadAsync(
    MinioImageProvider key,
    ImageDecoderCallback decode,
    StreamController<ImageChunkEvent> chunkEvents,
  ) async {
    Dio? dio;
    try {
      developer.log('开始加载图片: ${key.url}', name: 'MinioImageProvider');

      // 处理URL，确保正确的Content-Type
      final processedUrl = _processUrl(key.url);
      final uri = Uri.parse(processedUrl);
      developer.log('处理后的URL: $processedUrl', name: 'MinioImageProvider');

      // 构建基本请求头
      final Map<String, String> requestHeaders = {
        'Accept': 'image/jpeg,image/png,image/*,*/*;q=0.8',
        'Host': uri.authority,
        'Origin': '${uri.scheme}://${uri.authority}',
        'Referer': '${uri.scheme}://${uri.authority}',
        'Cache-Control': 'no-cache',
        'Pragma': 'no-cache',
        if (key.headers != null) ...key.headers!,
      };

      developer.log('请求头: $requestHeaders', name: 'MinioImageProvider');

      dio = Dio(
        BaseOptions(
          validateStatus: (status) => true, // 允许所有状态码，以便我们自己处理
          followRedirects: true,
          maxRedirects: 5,
          receiveDataWhenStatusError: true,
          headers: requestHeaders,
          responseType: ResponseType.bytes,
          receiveTimeout: const Duration(seconds: 15), // 缩短超时时间
          sendTimeout: const Duration(seconds: 15),
          connectTimeout: const Duration(seconds: 10), // 添加连接超时
        ),
      );

      // 添加详细的请求日志
      dio.interceptors.add(
        LogInterceptor(
          requestHeader: true,
          requestBody: false,
          responseHeader: true,
          responseBody: false,
          error: true,
          logPrint: (obj) {
            developer.log(obj.toString(), name: 'MinioImageProvider');
          },
        ),
      );

      final response = await dio
          .get<List<int>>(
            processedUrl,
            onReceiveProgress: (count, total) {
              if (total != -1) {
                chunkEvents.add(
                  ImageChunkEvent(
                    cumulativeBytesLoaded: count,
                    expectedTotalBytes: total,
                  ),
                );
              }
            },
          )
          .timeout(
            const Duration(seconds: 30),
            onTimeout: () {
              throw TimeoutException('图片加载超时，请检查网络连接后重试');
            },
          );

      // 详细的响应日志
      final responseLog =
          StringBuffer()
            ..writeln('响应状态码: ${response.statusCode}')
            ..writeln('Content-Type: ${response.headers.value('content-type')}')
            ..writeln(
              'Content-Length: ${response.headers.value('content-length')}',
            )
            ..writeln('URL: $processedUrl');

      if (response.headers.map.isNotEmpty) {
        responseLog.writeln('响应头:');
        response.headers.map.forEach((key, value) {
          responseLog.writeln('  $key: $value');
        });
      }

      developer.log(responseLog.toString(), name: 'MinioImageProvider');

      // 处理不同的错误状态码
      switch (response.statusCode) {
        case 200:
          break; // 继续处理
        case 403:
          throw Exception('访问被拒绝：可能是授权已过期，请刷新页面重试');
        case 404:
          throw Exception('图片不存在或已被删除');
        case 500:
          throw Exception('服务器内部错误，请稍后重试');
        default:
          throw Exception('图片加载失败: HTTP ${response.statusCode}');
      }

      if (response.data == null || response.data!.isEmpty) {
        throw Exception('图片数据为空');
      }

      final bytes = Uint8List.fromList(response.data!);

      // 验证图片数据
      if (bytes.length < 4) {
        throw Exception('无效的图片数据：数据长度过短');
      }

      // 检查图片格式的魔数
      final header = bytes.sublist(0, 4);
      if (!_isValidImageHeader(header)) {
        final contentType = response.headers.value('content-type') ?? '未知';
        throw Exception('无效的图片格式：收到的内容类型为 $contentType');
      }

      developer.log(
        '图片加载成功:\n'
        '大小: ${bytes.length} bytes\n'
        'Content-Type: ${response.headers.value('content-type')}',
        name: 'MinioImageProvider',
      );

      final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
      final descriptor = await decode(buffer);

      await chunkEvents.close();
      return descriptor;
    } catch (e, stack) {
      final errorMessage =
          StringBuffer()
            ..writeln('图片加载失败:')
            ..writeln('错误: $e')
            ..writeln('堆栈: $stack')
            ..writeln('URL: ${key.url}');

      developer.log(errorMessage.toString(), name: 'MinioImageProvider');

      await chunkEvents.close();

      // 重新抛出一个更友好的错误消息
      if (e is DioException) {
        switch (e.type) {
          case DioExceptionType.connectionTimeout:
            throw Exception('连接服务器超时，请检查网络连接是否正常');
          case DioExceptionType.sendTimeout:
            throw Exception('发送请求超时，请检查网络连接是否稳定');
          case DioExceptionType.receiveTimeout:
            throw Exception('接收数据超时，图片可能太大或网络不稳定');
          case DioExceptionType.badResponse:
            throw Exception('服务器返回错误：${e.response?.statusCode ?? "未知状态码"}');
          case DioExceptionType.cancel:
            throw Exception('图片加载已取消');
          case DioExceptionType.connectionError:
            throw Exception('网络连接错误，请检查网络是否正常');
          default:
            throw Exception('网络错误：${e.message}');
        }
      } else if (e is TimeoutException) {
        throw Exception('图片加载超时，请检查网络连接后重试');
      }
      rethrow;
    } finally {
      dio?.close(force: true);
    }
  }

  /// 检查图片头部魔数是否有效
  bool _isValidImageHeader(List<int> header) {
    try {
      // JPEG (FF D8 FF)
      if (header[0] == 0xFF && header[1] == 0xD8 && header[2] == 0xFF) {
        return true;
      }
      // PNG (89 50 4E 47)
      if (header[0] == 0x89 &&
          header[1] == 0x50 &&
          header[2] == 0x4E &&
          header[3] == 0x47) {
        return true;
      }
      // GIF (47 49 46 38)
      if (header[0] == 0x47 &&
          header[1] == 0x49 &&
          header[2] == 0x46 &&
          header[3] == 0x38) {
        return true;
      }
      // WEBP (52 49 46 46)
      if (header[0] == 0x52 &&
          header[1] == 0x49 &&
          header[2] == 0x46 &&
          header[3] == 0x46) {
        return true;
      }
      return false;
    } catch (e) {
      developer.log('检查图片头部出错: $e', name: 'MinioImageProvider');
      return false;
    }
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other.runtimeType != runtimeType) return false;
    return other is MinioImageProvider &&
        other.url == url &&
        other.scale == scale;
  }

  @override
  int get hashCode => Object.hash(url, scale);

  @override
  String toString() =>
      '${objectRuntimeType(this, 'MinioImageProvider')}("$url", scale: $scale)';
}
